package com.nb.service.impl;

import com.nb.mapper.AdminMapper;
import com.nb.service.AdminService;
import com.nb.utils.CurrentHolderUtil;
import com.nb.vo.admin.*;
import com.nb.vo.admin.BodyOV.AdminHostitalUpdate;
import com.nb.vo.admin.BodyOV.AdminSettingUpdateCost;
import com.nb.vo.admin.BodyOV.AdminUsersAdd;
import com.nb.vo.admin.BodyOV.AdminUsersUpdate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AdminServiceImpl implements AdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Value("${spring.datasource.url}")
    private String datasourceUrl;

    @Value("${spring.datasource.username}")
    private String datasourceUsername;

    @Value("${spring.datasource.password}")
    private String datasourcePassword;

    @Value("${backup.path}")
    private String backupPath;

    @Override
    public List<AdminGetUsers> getAllUsers() {

            List<AdminGetUsers> allUsers1 = adminMapper.getAllUsers();
            List<AdminGetUsers> allUsers2 = adminMapper.getAllUsers2();
            List<AdminGetUsers> allUsers = new ArrayList<>();
            allUsers.addAll(allUsers2);
            allUsers.addAll(allUsers1);

            return allUsers;
    }

    @Override
    @Transactional
    public boolean updateUser(AdminUsersUpdate body) {
        int flag2 = 0;

        String oldpasswor = adminMapper.getPasswordById(body);
        String newpasswor = body.getPassword();
        if(!oldpasswor.equals(newpasswor)) {
            String encryptedPassword = DigestUtils.md5DigestAsHex(body.getPassword().getBytes());
            body.setPassword(encryptedPassword);
            flag2 = adminMapper.updateUserPassword(body);
        }

        String title = body.getPosition();
        int flag1 = 0;
        if(title != null) {
           flag1 = adminMapper.updateDoctorTitle(body);
        }

        return (flag1 > 0 || flag2 > 0);
    }

    @Override
    public boolean deleteUser(String id) {

        return adminMapper.deleteUser(Integer.valueOf(id)) > 0;
    }

    @Override
    @Transactional
    public boolean addUser(AdminUsersAdd body) {

        String encryptedPassword = DigestUtils.md5DigestAsHex(body.getPassword().getBytes());
        body.setPassword(encryptedPassword);
        int flag = adminMapper.addUser(body);

        String userId = adminMapper.getuserIdByAcount(body);
        body.setUserId(userId);

        if (Objects.equals(body.getRole(), "医生")){
            adminMapper.addDoctor(body);
        } else if (Objects.equals(body.getRole(), "护士")){
            adminMapper.addNurse(body);
        } else if (Objects.equals(body.getRole(), "患者")){
            adminMapper.addPatient(body);
        }

        return flag > 0;
    }

    @Override
    public boolean updateAddAdmin(String id) {

        return adminMapper.updateAddAdmin(Integer.valueOf(id)) > 0;
    }

    @Override
    public boolean updateDeleteAdmin(String id) {
        return adminMapper.updateDeteteAdmin(Integer.valueOf(id)) > 0;
    }

    @Override
    public AdminSettingBase getHospitalInfo() {
        AdminSettingBase hospital = adminMapper.getHospital();
        return hospital;
    }

    @Override
    public boolean updateHospitalInfo(AdminHostitalUpdate body) {

        return adminMapper.updateHospital(body) > 0;
    }

    @Override
    public List<AdminSettingStructure> getSettingStructure() {

        return adminMapper.selectStructure();
    }

    @Override
    public TwoArrReturn getSettingConsultation() {
        List<AdminSettingConsultation> list = adminMapper.selectConsultation();

        Map<String, Integer> dateCountMap = list.stream()
                .collect(Collectors.toMap(
                        AdminSettingConsultation::getDate,
                        AdminSettingConsultation::getCount
                ));

        // 确定日期范围 - 从昨天开始往前7天
        LocalDate endDate = LocalDate.now().minusDays(1); // 昨天
        LocalDate startDate = endDate.minusDays(6); // 7天前（包含昨天共7天）

        List<String> dateList = new ArrayList<>();
        List<Integer> countList = new ArrayList<>();

        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MM/dd");

        // 遍历7天的日期（从早到晚）
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            // 添加格式化后的日期
            dateList.add(date.format(outputFormatter));

            // 添加对应的计数值（没有则为0）
            countList.add(dateCountMap.getOrDefault(date.format(inputFormatter), 0));
        }

        // 转换为数组
        String[] dateArray = dateList.toArray(new String[0]);
        Integer[] countArray = countList.toArray(new Integer[0]);

        // 输出结果
//        System.out.println("日期数组（从7天前到昨天）: " + Arrays.toString(dateArray));
//        System.out.println("计数数组: " + Arrays.toString(countArray));

        TwoArrReturn ov = new TwoArrReturn(dateArray,countArray);

        return ov;
    }

    @Override
    public TwoArrReturn getSettingAppointment() {
        List<AdminSettingAppointment> list = adminMapper.selectAppointment();

        Map<String, Integer> dateCountMap = list.stream()
                .collect(Collectors.toMap(
                        AdminSettingAppointment::getDate,
                        AdminSettingAppointment::getCount
                ));

        // 确定日期范围 - 从明天开始到6天后（共7天）
        LocalDate startDate = LocalDate.now().plusDays(1); // 明天
        LocalDate endDate = startDate.plusDays(6); // 7天后

        List<String> dateList = new ArrayList<>();
        List<Integer> countList = new ArrayList<>();

        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MM/dd");

        // 遍历7天的日期
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            // 添加格式化后的日期
            dateList.add(date.format(outputFormatter));

            // 添加对应的计数值（没有则为0）
            countList.add(dateCountMap.getOrDefault(date.format(inputFormatter), 0));
        }

        // 转换为数组
        String[] dateArray = dateList.toArray(new String[0]);
        Integer[] countArray = countList.toArray(new Integer[0]);


        TwoArrReturn ov = new TwoArrReturn(dateArray,countArray);

        return ov;
    }

    @Override
    public List<AdminPermissions> getPermissions() {

        return adminMapper.selectPermissions();
    }

    @Override
    public List<AdminSettingCost> getSettingCost() {

        return adminMapper.selectCost();
    }

    @Override
    public boolean updateSettingCost(List<AdminSettingUpdateCost> body) {
        int flag = 0;
        for (AdminSettingUpdateCost cost : body) {
            flag = 0;
           flag = adminMapper.updateCost(cost);
        }
        return flag > 0;
    }

    @Override
    public String backupData() {
        Integer userId = CurrentHolderUtil.getCurrentId();
        String role = adminMapper.getRoleById(userId);

        if(!"管理员".equals(role)) {
            throw new RuntimeException("非管理员用户无权进行数据备份操作");
        }

        // 创建备份目录
        File backupDir = new File(backupPath);
        if (!backupDir.exists()) {
            backupDir.mkdirs();
        }

        // 生成备份文件名
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String backupFileName = "backup_" + sdf.format(new Date()) + ".sql";
        String backupFilePath = backupPath + File.separator + backupFileName;

        try {
            // 从JDBC URL中提取数据库名
            String dbName = extractDatabaseName(datasourceUrl);
            if (dbName == null) {
                throw new RuntimeException("无法从JDBC URL中提取数据库名");
            }

            // 判断操作系统类型
            boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");

            Process process;
            if (isWindows) {
                // Windows环境下的命令
                String command = String.format(
                        "mysqldump -u%s -p%s %s > \"%s\"",
                        datasourceUsername,
                        datasourcePassword,
                        dbName,
                        backupFilePath
                );
                process = Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", command });
            } else {
                // Linux/Unix环境下的命令
                String command = String.format(
                        "mysqldump -u%s -p%s %s > %s",
                        datasourceUsername,
                        datasourcePassword,
                        dbName,
                        backupFilePath
                );
                process = Runtime.getRuntime().exec(new String[] { "sh", "-c", command });
            }

            int exitCode = process.waitFor();

            if (exitCode != 0) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    StringBuilder errorMsg = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        errorMsg.append(line).append("\n");
                    }
                    throw new RuntimeException("备份命令执行失败: " + errorMsg.toString());
                }
            }

            // 获取文件大小
            File backupFile = new File(backupFilePath);
            long fileSize = backupFile.length();

            // 记录备份信息到数据库
            Map<String, Object> params = new HashMap<>();
            params.put("name", backupFileName);
            params.put("path", backupFilePath);
            params.put("size", fileSize);
            params.put("description", "系统数据备份");
            params.put("creatorId", userId);

            adminMapper.insertBackupRecord(params);

            return backupFilePath;

        } catch (Exception e) {
            log.error("数据备份失败", e);
            throw new RuntimeException("数据备份失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean restoreData(MultipartFile file) {
        Integer userId = CurrentHolderUtil.getCurrentId();
        String role = adminMapper.getRoleById(userId);

        if(!"管理员".equals(role)) {
            throw new RuntimeException("非管理员用户无权进行数据恢复操作");
        }

        if (file == null || file.isEmpty()) {
            throw new RuntimeException("备份文件不能为空");
        }

        try {
            // 获取数据库名
            String dbName = extractDatabaseName(datasourceUrl);
            if (dbName == null) {
                throw new RuntimeException("无法从JDBC URL中提取数据库名");
            }

            // 创建临时文件保存上传的SQL
            Path tempFile = Files.createTempFile("restore_", ".sql");
            file.transferTo(tempFile.toFile());
            String sqlFilePath = tempFile.toAbsolutePath().toString();

            log.info("临时SQL文件已创建: {}", sqlFilePath);

            // 判断操作系统类型
            boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");

            Process process;
            if (isWindows) {
                // Windows环境下的命令
                String command = String.format(
                        "mysql -u%s -p%s %s < \"%s\"",
                        datasourceUsername,
                        datasourcePassword,
                        dbName,
                        sqlFilePath
                );
                process = Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", command });
            } else {
                // Linux/Unix环境下的命令
                String command = String.format(
                        "mysql -u%s -p%s %s < %s",
                        datasourceUsername,
                        datasourcePassword,
                        dbName,
                        sqlFilePath
                );
                process = Runtime.getRuntime().exec(new String[] { "sh", "-c", command });
            }

            int exitCode = process.waitFor();

            // 清理临时文件
            Files.deleteIfExists(tempFile);

            if (exitCode != 0) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    StringBuilder errorMsg = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        errorMsg.append(line).append("\n");
                    }
                    throw new RuntimeException("恢复命令执行失败: " + errorMsg.toString());
                }
            }

            log.info("数据恢复成功完成");
            return true;
        } catch (Exception e) {
            log.error("数据恢复失败", e);
            throw new RuntimeException("数据恢复失败: " + e.getMessage());
        }
    }

    @Override
    public List<BackupRecordVO> getBackupRecords() {
        Integer userId = CurrentHolderUtil.getCurrentId();
        log.info("正在获取用户角色，用户ID: {}", userId);

        // 添加超时处理
        String role;
        try {
            role = adminMapper.getRoleById(userId);
            log.info("获取到用户角色: {}", role);
        } catch (Exception e) {
            log.error("获取用户角色失败", e);
            throw new RuntimeException("获取用户权限信息失败，请稍后重试");
        }

        if(!"管理员".equals(role)) {
            throw new RuntimeException("非管理员用户无权查看备份记录");
        }

        try {
            List<BackupRecordVO> records = adminMapper.getBackupRecords();
            return records;
        } catch (Exception e) {
            log.error("获取备份记录失败", e);
            throw new RuntimeException("获取备份记录失败: " + e.getMessage());
        }
    }

    @Override
    public byte[] downloadBackup(Integer id) {
        Integer userId = CurrentHolderUtil.getCurrentId();
        String role = adminMapper.getRoleById(userId);

        if(!"管理员".equals(role)) {
            throw new RuntimeException("非管理员用户无权下载备份文件");
        }

        // 获取备份文件路径
        String filePath = adminMapper.getBackupFilePath(id);
        if (filePath == null) {
            throw new RuntimeException("未找到备份记录");
        }

        try {
            Path path = Paths.get(filePath);
            log.info("备份文件路径: {}", path.toAbsolutePath());
            return Files.readAllBytes(path);
        } catch (IOException e) {
            log.error("下载备份文件失败", e);
            throw new RuntimeException("下载备份文件失败: " + e.getMessage());
        }
    }

    /**
     * 从JDBC URL中提取数据库名
     */
    private String extractDatabaseName(String jdbcUrl) {
        // 假设URL格式为jdbc:mysql://hostname:port/database
        int lastSlashIndex = jdbcUrl.lastIndexOf('/');
        if (lastSlashIndex != -1) {
            String dbNameWithParams = jdbcUrl.substring(lastSlashIndex + 1);
            // 处理可能的参数
            int questionMarkIndex = dbNameWithParams.indexOf('?');
            if (questionMarkIndex != -1) {
                return dbNameWithParams.substring(0, questionMarkIndex);
            }
            return dbNameWithParams;
        }
        return null;
    }
}
